//
//  ViewController.m
//  SSL_Runtime_Learn
//
//  Created by SSLong on 2018/2/7.
//  Copyright © 2018年 sunshilong. All rights reserved.
//

#import "ViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "NSObject+KeyValue.h"
#import "Person.h"
#import "School.h"

static char associateButtonKey;

@interface ViewController ()<PersonDelegate,UITableViewDelegate>
{
    unsigned int count;
    
}

@property (weak, nonatomic) IBOutlet UIButton *btnAssociate;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self getPropertys];
    [self getIvars];
    [self getMethods];
    
    Person *person = [[Person alloc] init];
    
    person.name = @"Deve";
    person.idcard = @"123456";
    person.age = @18;
    person.height = @170.0;
    person.delegate = self;
    [person initAperson];
    
    [self getProtocols];
    
    //
    //隐式调用方法
    [self performSelector:@selector(resolveAdd:) withObject:@"test"];
    
    //4、关联对象
    //设置关联对象
    objc_setAssociatedObject(_btnAssociate, &associateButtonKey, @"天津恒达", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    _btnAssociate.tag = 999;
    
    //自动归档
    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"person.data"];//名字取什么都行
    [NSKeyedArchiver archiveRootObject:person toFile:filePath];//归档
    
    
}
#pragma mark --- 1
#pragma mark --- 获取属性列表
- (void)getPropertys{
    objc_property_t *propertys = class_copyPropertyList([Person class], &count);
    for (unsigned int i=0; i<count; i++) {
        const char *propertyName = property_getName(propertys[i]);
        NSLog(@"属性名字-----%@",[NSString stringWithUTF8String:propertyName]);
    }
}
#pragma mark --- 获取方法列表
- (void)getMethods{
    
    Method *methods = class_copyMethodList([Person class], &count);
    for (unsigned int i = 0; i<count; i++) {
        Method method = methods[i];
        NSLog(@"属性方法---->%@", NSStringFromSelector(method_getName(method)));
    }
    
}
#pragma mark --- 获取成员变量
- (void)getIvars{
    Ivar *ivars = class_copyIvarList([Person class], &count);
    for (unsigned int i=0; i<count; i++) {
        Ivar myIvar = ivars[i];
        const char *ivarName = ivar_getName(myIvar);
        NSLog(@"成员变量---->%@", [NSString stringWithUTF8String:ivarName]);
    }
    
}
#pragma mark --- 获取协议列表
- (void)getProtocols{
    __unsafe_unretained Protocol **protocols = class_copyProtocolList([self class], &count);
    for (unsigned int i=0; i<count; i++) {
        Protocol *myProtocal = protocols[i];
        const char *protocolName = protocol_getName(myProtocal);
        NSLog(@"协议列表---->%@", [NSString stringWithUTF8String:protocolName]);
    }
    
}
- (void)getBack{
    NSLog(@"代理方法");
    //测试
    [self readArchiver];//1、读档
    [self keyValueExchange];//2、字典转模型，模型转字典
    [self forwerdingMethod];//动态解析
}
#pragma mark ---- 二、方法执行
//super，直接执行父类方法也是方法拦截
#pragma mark ---- 三、动态添加方法
void runAddMethod(id self, SEL _cmd, NSString *string){
    NSLog(@"add C IMP ", string);
}
#pragma mark--- 给self对象监视方法是否存在
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    
    //给本类动态添加一个方法
    if ([NSStringFromSelector(sel) isEqualToString:@"resolveAdd:"]) {
        class_addMethod(self, sel, (IMP)runAddMethod, "v@:*");
    }
    return YES;
}

#pragma mark--- 四、关联对象

- (IBAction)action_tapAssociate:(UIButton *)sender {
    //获取关联对象
    NSString *string = objc_getAssociatedObject(sender, &associateButtonKey);
    NSLog(@"出发关联对象 = %@ tag=%ld", string,sender.tag);
}

#pragma mark --- 五、归档解档
- (void)readArchiver{
    //获取归档地址
    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"person.data"];
    Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    
    NSLog(@"person's name is %@,and age is = %ld",person.name,person.age);
}
#pragma mark --- 六、字典和模型互转
- (void)keyValueExchange{
    NSDictionary *dic = @{@"name":@"李磊",
                          @"idcard":@"888888",
                          @"age":@5,
                          @"height":@170.0,
                          @"student":@{
                                  @"name":@"Halen"
                                  }
                          };
    //字典转模型
    Person *person = [Person objectInitWithDictionary:dic];
    NSLog(@"\n person's name is %@,\n person'age is %ld,\n person'height is %f",person.name,[person.age integerValue],[person.height floatValue]);
    
    //模型转字典
    NSDictionary *dict = [person dictionaryWithObject];
    NSLog(@"转换后的字典是\n%@",dict);
}
#pragma mark --- 动态方法解析
- (void)forwerdingMethod{
    //School这个对象调用了他没有的方法haveClass，但是Teacher这个对象有这个方法，此时就可以用方法动态解析来处理了
    School *school = [[School alloc] init];
    ((void (*) (id, SEL)) objc_msgSend) (school,sel_registerName("haveClass"));
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
